{
 "cells": [
  {
   "cell_type": "raw",
   "metadata": {
    "vscode": {
     "languageId": "raw"
    }
   },
   "source": [
    "---\n",
    "title: Control flow\n",
    "description: Mojo control flow statements.\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Mojo includes several traditional control flow structures for conditional and\n",
    "repeated execution of code blocks.\n",
    "\n",
    "## The `if` statement\n",
    "\n",
    "Mojo supports the `if` statement for conditional code execution. With it you can\n",
    "conditionally execute an indented code block if a given\n",
    "[boolean](/mojo/manual/types#booleans) expression evaluates to `True`.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "It is warm.\n",
      "The temperature is 77.0 Fahrenheit.\n"
     ]
    }
   ],
   "source": [
    "temp_celsius = 25\n",
    "if temp_celsius > 20:\n",
    "    print(\"It is warm.\")\n",
    "    print(\"The temperature is\", temp_celsius * 9 / 5 + 32, \"Fahrenheit.\" )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can write the entire `if` statement as a single line if all you need to\n",
    "execute conditionally is a single, short statement."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "It is warm.\n"
     ]
    }
   ],
   "source": [
    "temp_celsius = 22\n",
    "if temp_celsius < 15: print(\"It is cool.\") # Skipped because condition is False\n",
    "if temp_celsius > 20: print(\"It is warm.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Optionally, an `if` statement can include any number of additional `elif`\n",
    "clauses, each specifying a boolean condition and associated code block to\n",
    "execute if `True`. The conditions are tested in the order given. When a\n",
    "condition evaluates to `True`, the associated code block is executed and no\n",
    "further conditions are tested.\n",
    "\n",
    "Additionally, an `if` statement can include an optional `else` clause providing\n",
    "a code block to execute if all conditions evaluate to `False`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "It is warm.\n"
     ]
    }
   ],
   "source": [
    "temp_celsius = 25\n",
    "if temp_celsius <= 0:\n",
    "    print(\"It is freezing.\")\n",
    "elif temp_celsius < 20:\n",
    "    print(\"It is cool.\")\n",
    "elif temp_celsius < 30:\n",
    "    print(\"It is warm.\")\n",
    "else:\n",
    "    print(\"It is hot.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ":::note TODO\n",
    "\n",
    "Mojo currently does not support the equivalent of a Python `match` or C `switch`\n",
    "statement for pattern matching and conditional execution.\n",
    "\n",
    ":::"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Short-circuit evaluation\n",
    "\n",
    "Mojo follows [short-circuit evaluation](https://en.wikipedia.org/wiki/Short-circuit_evaluation)\n",
    "semantics for boolean operators. If the first argument to an `or` operator\n",
    "evaluates to `True`, the second argument is not evaluated.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Short-circuit \"or\" evaluation\n",
      "Executing true_func\n",
      "True result\n"
     ]
    }
   ],
   "source": [
    "def true_func() -> Bool:\n",
    "    print(\"Executing true_func\")\n",
    "    return True\n",
    "\n",
    "def false_func() -> Bool:\n",
    "    print(\"Executing false_func\")\n",
    "    return False\n",
    "\n",
    "print('Short-circuit \"or\" evaluation')\n",
    "if true_func() or false_func():\n",
    "    print(\"True result\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If the first argument to an `and` operator evaluates to `False`, the second\n",
    "argument is not evaluated."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Short-circuit \"and\" evaluation\n",
      "Executing false_func\n"
     ]
    }
   ],
   "source": [
    "print('Short-circuit \"and\" evaluation')\n",
    "if false_func() and true_func():\n",
    "    print(\"True result\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Conditional expressions\n",
    "\n",
    "Mojo also supports conditional expressions (or what is sometimes called a\n",
    "[_ternary conditional operator_](https://en.wikipedia.org/wiki/Ternary_conditional_operator))\n",
    "using the syntax<code><var>true_result</var> if <var>boolean_expression</var> else <var>false_result</var></code>, just as\n",
    "in Python. This is most often used as a concise way to assign one of two\n",
    "different values to a variable, based on a boolean condition."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The forecast for today is cool\n"
     ]
    }
   ],
   "source": [
    "temp_celsius = 15\n",
    "forecast = \"warm\" if temp_celsius > 20 else \"cool\"\n",
    "print(\"The forecast for today is\", forecast)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The alternative, written as a multi-line `if` statement, is more verbose."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The forecast for today is cool\n"
     ]
    }
   ],
   "source": [
    "if temp_celsius > 20:\n",
    "    forecast = \"warm\"\n",
    "else:\n",
    "    forecast = \"cool\"\n",
    "print(\"The forecast for today is\", forecast)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The `while` statement\n",
    "\n",
    "The `while` loop repeatedly executes a code block while a given boolean\n",
    "expression evaluates to `True`. For example, the following loop prints values\n",
    "from the Fibonacci series that are less than 50."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0, 1, 1, 2, 3, 5, 8, 13, 21, 34"
     ]
    }
   ],
   "source": [
    "fib_prev = 0\n",
    "fib_curr = 1\n",
    "\n",
    "print(fib_prev, end=\"\")\n",
    "while fib_curr < 50:\n",
    "    print(\",\", fib_curr, end=\"\")\n",
    "    fib_prev, fib_curr = fib_curr, fib_prev + fib_curr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A `continue` statement skips execution of the rest of the code block and\n",
    "resumes with the loop test expression."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1, 2, 4, 5, "
     ]
    }
   ],
   "source": [
    "n = 0\n",
    "while n < 5:\n",
    "    n += 1\n",
    "    if n == 3:\n",
    "        continue\n",
    "    print(n, end=\", \")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A `break` statement terminates execution of the loop."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1, 2, "
     ]
    }
   ],
   "source": [
    "n = 0\n",
    "while n < 5:\n",
    "    n += 1\n",
    "    if n == 3:\n",
    "        break\n",
    "    print(n, end=\", \")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Optionally, a `while` loop can include an `else` clause. The body of the `else`\n",
    "clause executes when the loop's boolean condition evaluates to `False`, even if\n",
    "it occurs the first time tested."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Loop completed\n"
     ]
    }
   ],
   "source": [
    "n = 5\n",
    "\n",
    "while n < 4:\n",
    "    print(n)\n",
    "    n += 1\n",
    "else:\n",
    "    print(\"Loop completed\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ":::note\n",
    "\n",
    "The `else` clause does _not_ execute if a `break` or `return` statement\n",
    "exits the `while` loop.\n",
    "\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n"
     ]
    }
   ],
   "source": [
    "n = 0\n",
    "while n < 5:\n",
    "    n += 1\n",
    "    if n == 3:\n",
    "        break\n",
    "    print(n)\n",
    "else:\n",
    "    print(\"Executing else clause\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The `for` statement\n",
    "\n",
    "The `for` loop iterates over a sequence, executing a code block for each\n",
    "element in the sequence.\n",
    "The Mojo `for` loop can iterate over any type that implements an `__iter__()`\n",
    "method that returns a type that defines `__next__()` and `__len__()` methods.\n",
    "\n",
    "### Iterating over Mojo collections\n",
    "\n",
    "All of the collection types in the [`collections`](/mojo/stdlib/collections)\n",
    "module support `for` loop iteration. See the\n",
    "[Collection types](/mojo/manual/types#collection-types) documentation for more\n",
    "information on Mojo collection types.\n",
    "\n",
    ":::caution TODO\n",
    "\n",
    "Iterating over Mojo native collections currently assigns the loop index variable\n",
    "a [`Reference`](/mojo/stdlib/memory/reference/Reference) to each item, not the\n",
    "item itself. You can access the item using the dereference operator, `[]`, as\n",
    "shown in the examples below. This may change in a future version of Mojo.\n",
    "\n",
    ":::\n",
    "\n",
    "The following shows an example of iterating over a Mojo\n",
    "[`List`](/mojo/stdlib/collections/list/List)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "California\n",
      "Hawaii\n",
      "Oregon\n"
     ]
    }
   ],
   "source": [
    "from collections import List\n",
    "\n",
    "states = List[String](\"California\", \"Hawaii\", \"Oregon\")\n",
    "for state in states:\n",
    "    print(state[])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The same technique works for iterating over a Mojo\n",
    "[`Set`](/mojo/stdlib/collections/set/Set)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "42\n",
      "0\n"
     ]
    }
   ],
   "source": [
    "from collections import Set\n",
    "\n",
    "values = Set[Int](42, 0)\n",
    "for item in values:\n",
    "    print(item[])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There are two techniques for iterating over a Mojo\n",
    "[`Dict`](/mojo/stdlib/collections/dict/Dict). The first is to iterate directly\n",
    "using the `Dict`, which produces a sequence of the dictionary's keys."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sacramento, California\n",
      "Honolulu, Hawaii\n",
      "Salem, Oregon\n"
     ]
    }
   ],
   "source": [
    "from collections import Dict\n",
    "\n",
    "capitals = Dict[String, String]()\n",
    "capitals[\"California\"] = \"Sacramento\"\n",
    "capitals[\"Hawaii\"] = \"Honolulu\"\n",
    "capitals[\"Oregon\"] = \"Salem\"\n",
    "\n",
    "for state in capitals:\n",
    "    print(capitals[state[]] + \", \" + state[])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The second approach to iterating over a Mojo `Dict` is to invoke its\n",
    "[`items()`](/mojo/stdlib/collections/dict/Dict#items) method, which produces a\n",
    "sequence of [`DictEntry`](/mojo/stdlib/collections/dict/DictEntry) objects.\n",
    "Within the loop body, you can then access the `key` and `value` fields of the\n",
    "entry."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sacramento, California\n",
      "Honolulu, Hawaii\n",
      "Salem, Oregon\n"
     ]
    }
   ],
   "source": [
    "for item in capitals.items():\n",
    "    print(item[].value + \", \" + item[].key)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Another type of iterable provided by the Mojo standard library is a _range_,\n",
    "which is a sequence of integers generated by the\n",
    "[`range()`](/mojo/stdlib/builtin/range/range) function. It differs from the\n",
    "collection types shown above in that it's implemented as a\n",
    "[generator](https://en.wikipedia.org/wiki/Generator_(computer_programming)),\n",
    "producing each value as needed rather than materializing the entire sequence\n",
    "in memory. Additionally, each value assigned to the loop index variable is\n",
    "simply the `Int` value rather than a `Reference` to the value, so you should\n",
    "not use the dereference operator on it within the loop. For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0, 1, 2, 3, 4, "
     ]
    }
   ],
   "source": [
    "for i in range(5):\n",
    "    print(i, end=\", \")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `for` loop control statements\n",
    "\n",
    "A `continue` statement skips execution of the rest of the code block and\n",
    "resumes the loop with the next element of the collection."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0, 1, 2, 4, "
     ]
    }
   ],
   "source": [
    "for i in range(5):\n",
    "    if i == 3:\n",
    "        continue\n",
    "    print(i, end=\", \")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A `break` statement terminates execution of the loop."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0, 1, 2, "
     ]
    }
   ],
   "source": [
    "for i in range(5):\n",
    "    if i == 3:\n",
    "        break\n",
    "    print(i, end=\", \")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Optionally, a `for` loop can include an `else` clause. The body of the `else`\n",
    "clause executes after iterating over all of the elements in a collection."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0, 1, 2, 3, 4, \n",
      "Finished executing 'for' loop\n"
     ]
    }
   ],
   "source": [
    "for i in range(5):\n",
    "    print(i, end=\", \")\n",
    "else:\n",
    "    print(\"\\nFinished executing 'for' loop\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `else` clause executes even if the collection is empty."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Finished executing 'for' loop\n"
     ]
    }
   ],
   "source": [
    "from collections import List\n",
    "\n",
    "empty = List[Int]()\n",
    "for i in empty:\n",
    "    print(i[])\n",
    "else:\n",
    "    print(\"Finished executing 'for' loop\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ":::note\n",
    "\n",
    "The `else` clause does _not_ execute if a `break` or `return` statement\n",
    "terminates the `for` loop.\n",
    "\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found a dog\n"
     ]
    }
   ],
   "source": [
    "from collections import List\n",
    "\n",
    "animals = List[String](\"cat\", \"aardvark\", \"hippopotamus\", \"dog\")\n",
    "for animal in animals:\n",
    "    if animal[] == \"dog\":\n",
    "        print(\"Found a dog\")\n",
    "        break\n",
    "else:\n",
    "    print(\"No dog found\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Iterating over Python collections\n",
    "\n",
    "The Mojo `for` loop supports iterating over Python collection types. Each item\n",
    "retrieved by the loop is a\n",
    "[`PythonObject`](/mojo/stdlib/python/object/PythonObject) wrapper around\n",
    "the Python object. Refer to the [Python types](/mojo/manual/python/types)\n",
    "documentation for more information on manipulating Python objects from Mojo.\n",
    "\n",
    "The following is a simple example of iterating over a mixed-type Python list."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "42\n",
      "cat\n",
      "3.14159\n"
     ]
    }
   ],
   "source": [
    "from python import Python\n",
    "\n",
    "# Create a mixed-type Python list\n",
    "py_list = Python.evaluate(\"[42, 'cat', 3.14159]\")\n",
    "for py_obj in py_list:  # Each element is of type \"PythonObject\"\n",
    "    print(py_obj)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ":::note TODO\n",
    "\n",
    "Iterating over a Mojo collection currently assigns the loop index variable a\n",
    "`Reference` to each element, which then requires you to use the dereference\n",
    "operator within the loop body. In contrast, iterating over a Python collection\n",
    "assigns a `PythonObject` wrapper for the element, which does _not_ require you\n",
    "to use the dereference operator.\n",
    "\n",
    ":::\n",
    "\n",
    "\n",
    "There are two techniques for iterating over a Python dictionary. The first is to\n",
    "iterate directly using the dictionary, which produces a sequence of its keys."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a 1\n",
      "b 2.71828\n",
      "c sushi\n"
     ]
    }
   ],
   "source": [
    "from python import Python\n",
    "\n",
    "# Create a mixed-type Python dictionary\n",
    "py_dict = Python.evaluate(\"{'a': 1, 'b': 2.71828, 'c': 'sushi'}\")\n",
    "for py_key in py_dict:  # Each element is of type \"PythonObject\"\n",
    "    print(py_key, py_dict[py_key])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The second approach to iterating over a Python dictionary is to invoke its\n",
    "`items()` method, which produces a sequence of 2-tuple objects.\n",
    "Within the loop body, you can then access the key and value by index."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a 1\n",
      "b 2.71828\n",
      "c sushi\n"
     ]
    }
   ],
   "source": [
    "for py_tuple in py_dict.items():  # Each element is of type \"PythonObject\"\n",
    "    print(py_tuple[0], py_tuple[1])"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Mojo",
   "language": "mojo",
   "name": "mojo-jupyter-kernel"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "mojo"
   },
   "file_extension": ".mojo",
   "mimetype": "text/x-mojo",
   "name": "mojo"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
